# -*- python -*-
# ex: set syntax=python:
#
# Buildbot config for the Open Lighting Project.
# If you want to add slaves edit 'build.config'.
# The config is organized bottom-up, i.e. slaves, then builders, then
# schedulers.

from buildbot.buildslave import BuildSlave
from buildbot.changes import filter
from buildbot.changes.gitpoller import GitPoller
from buildbot.config import BuilderConfig
from buildbot.process.factory import BuildFactory
from buildbot.scheduler import Try_Userpass
from buildbot.schedulers.basic import SingleBranchScheduler
from buildbot.schedulers.forcesched import ForceScheduler
from buildbot.status import html
from buildbot.status import words
from buildbot.status.web import authz, auth
from buildbot.steps.shell import Compile
from buildbot.steps.shell import Configure
from buildbot.steps.shell import ShellCommand
from buildbot.steps.source import Git
import config_helper

config = config_helper.LoadConfig('build.config')
slaves = config_helper.SlaveStore(config['SLAVES'])

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

####### PROJECT IDENTITY

c['title'] = config['TITLE']
c['titleURL'] = config['URL']
c['buildbotURL'] = config['BUILDBOTURL']

####### CHANGESOURCES

# The 'change_source' setting tells the buildmaster how it should find out
# about source code changes.

c['change_source'] = [
    GitPoller(config['REPO'],
              workdir='gitpoller-workdir',
              branch='master',
              pollinterval=300),
]

####### BUILDSLAVES

c['slavePortnum'] = config['SLAVE_PORT']

# The 'slaves' list defines the set of recognized buildslaves. Each element is
# a BuildSlave object, specifying a unique slave name and password.
c['slaves'] = [BuildSlave(s.name(), s.password()) for s in slaves.GetSlaves()]

####### BUILDERS

# The 'builders' list defines the Builders, which tell Buildbot how to perform
# a build: what steps, and which slaves can execute them.  Note that any
# particular build will only take place on one slave.

# The main factory, to do fetch via git, autoreconf, configure, make & make
# check.
factory = BuildFactory()
# check out the source
factory.addStep(Git(repourl=config['REPO']))
factory.addStep(ShellCommand(command=["autoreconf", "-i"], name="autoreconf"))
#Should be able to switch to these with newer versions of buildbot
#factory.addStep(Configure(command=["./configure", "--enable-e133", "--enable-rdm-tests"]))
factory.addStep(ShellCommand(
    command=["./configure", "--enable-e133", "--enable-rdm-tests"],
    name="configure",
))
factory.addStep(Compile(
    description='building',
    descriptionDone='build',
    name='make',
    command=['make']))
factory.addStep(Compile(
    name='make check',
    description='testing',
    descriptionDone='test',
    command=['make', 'check']))

# cpplint factory
cpp_lint_command = (
    'cpplint.py %s $(find ./ -name "*.h" -or -name "*.cpp" | xargs)' %
    config['CPP_LINT_ARGS'])
cpp_lint_factory = BuildFactory()
cpp_lint_factory.addStep(Git(repourl=config['REPO']))
cpp_lint_factory.addStep(ShellCommand(
   command=cpp_lint_command,
   haltOnFailure=False,
   flunkOnFailure=False,
   warnOnWarnings=True,
   warnOnFailure=True,
   description='linting',
   descriptionDone='lint',
))

# jslint factory
js_lint_command = (
    'gjslint %s -r javascript/ola/' %
    config['JS_LINT_ARGS'])
js_lint_factory = BuildFactory()
js_lint_factory.addStep(Git(repourl=config['REPO']))
js_lint_factory.addStep(ShellCommand(
   command=js_lint_command,
   haltOnFailure=False,
   flunkOnFailure=False,
   warnOnWarnings=True,
   warnOnFailure=True,
   description='linting',
   descriptionDone='lint',
))

# heap check factory
hc_factory = BuildFactory()
hc_factory.addStep(Git(repourl=config['REPO']))
hc_factory.addStep(ShellCommand(command=["autoreconf", "-i"], name="autoreconf"))
hc_factory.addStep(Configure(
    command=["./configure", "--enable-e133", "--enable-tcmalloc"]))
hc_factory.addStep(Compile(
    name='make',
    description='building',
    descriptionDone='build',
    command=['make']))
hc_factory.addStep(Compile(
    description='testing',
    descriptionDone='test',
    command=['make', 'check'],
    env={'HEAPCHECK': 'normal'},
))

# doxygen doc factory
doc_factory = BuildFactory()
doc_factory.addStep(Git(repourl=config['REPO']))
doc_factory.addStep(ShellCommand(command=["autoreconf", "-i"], name="autoreconf"))
#Should be able to switch to these with newer versions of buildbot
#doc_factory.addStep(Configure(command=["./configure", "--enable-e133", "--enable-rdm-tests"]))
doc_factory.addStep(ShellCommand(
    command=["./configure"],
    name="configure",
))
doc_factory.addStep(Compile(
    name='make doxygen-doc',
    description='documenting',
    descriptionDone='documented',
    command=['make', 'doxygen-doc']))
doc_factory.addStep(ShellCommand(
  workdir="build",
  command=["./doxygen/copy-doc.sh", "/var/www/docs.openlighting.org/doc/"],
  name="copy"))

# man page factory
man_factory = BuildFactory()
man_factory.addStep(Git(repourl=config['REPO']))
#Should be able to switch to these with newer versions of buildbot
man_factory.addStep(ShellCommand(
  workdir="build/man",
  command=["./generate-html.sh", "/var/www/docs.openlighting.org/man/"],
  name="generate"))

c['builders'] = []

# Create a make, make check builder for each slave.
# TODO: We should probably just create a builder for each (platform, arch) and
# add all the slaves instead. No point running a build more than once in the
# same environment.
# PN: Although it depends if we want to be able to distinguish a build failing
# due to a bug related to openslp say, compared to the arch/OS in general
for slave in slaves.GetSlaves(config_helper.HasBuild):
  c['builders'].append(
      BuilderConfig(name=("buildcheck-ola-%s" % slave.name()),
                    slavenames=[slave.name()],
                    factory=factory,
                    #Slow slaves will merge requests, to try and reduce their
                    #Workload
                    mergeRequests=slave.is_slow))

cpp_lint_slaves = slaves.GetSlaves(config_helper.HasCPPLintFilter)
if cpp_lint_slaves:
  c['builders'].append(
      BuilderConfig(name="cpplint-ola",
        slavenames=[s.name() for s in cpp_lint_slaves],
        factory=cpp_lint_factory))

js_lint_slaves = slaves.GetSlaves(config_helper.HasJSLintFilter)
if js_lint_slaves:
  c['builders'].append(
      BuilderConfig(name="jslint-ola",
        slavenames=[s.name() for s in js_lint_slaves],
        factory=js_lint_factory))

tcmalloc_slaves = slaves.GetSlaves(config_helper.HasTCMalloc)
if tcmalloc_slaves:
  c['builders'].append(
      BuilderConfig(name="leakchecker-ola",
        slavenames=[s.name() for s in tcmalloc_slaves],
        factory=hc_factory))

doc_slaves = slaves.GetSlaves(config_helper.GenerateDoc)
c['builders'].append(
    BuilderConfig(name="doxygen-doc-generator",
      slavenames=[s.name() for s in doc_slaves],
      factory=doc_factory))

man_slaves = slaves.GetSlaves(config_helper.GenerateMan)
c['builders'].append(
    BuilderConfig(name="man-page-generator",
      slavenames=[s.name() for s in man_slaves],
      factory=man_factory))


####### SCHEDULERS

# Configure the Schedulers, which decide how to react to incoming changes.  In
# this case, just kick off a 'buildcheck' build

c['schedulers'] = [
    SingleBranchScheduler(
        name="all",
        change_filter=filter.ChangeFilter(branch='master'),
        treeStableTimer=None,
        builderNames=[b.name for b in c['builders']],
    ),
    ForceScheduler(
        name="force",
        builderNames=[b.name for b in c['builders']],
    ),
    Try_Userpass(name='try',
                 builderNames=[b.name for b in c['builders']],
                 port=5555,
                 userpass=[('sampleuser','samplepass')],
    ),
]


####### STATUS TARGETS

# 'status' is a list of Status Targets. The results of each build will be
# pushed to these targets. buildbot/status/*.py has a variety to choose from,
# including web pages, email senders, and IRC bots.

c['status'] = []

authz_cfg=authz.Authz(
    # change any of these to True to enable; see the manual for more
    # options
    auth=auth.BasicAuth([("ola","ola")]),
    gracefulShutdown = False,
    forceBuild = 'auth', # use this to test your slave once it is set up
    forceAllBuilds = False,
    pingBuilder = False,
    stopBuild = False,
    stopAllBuilds = False,
    cancelPendingBuild = False,
)
c['status'].append(
    html.WebStatus(
        http_port=8010,
        authz=authz_cfg,
        revlink=("%s%s" % (config['REPO'], config['REVLINKSTUB'])),))

#Reverting to one IRC bot, as buildbot doesn't seem to cope with two properly
#Quiet bot, temporarily in test channel, as it seems to be too chatty
#c['status'].append(words.IRC(host=config['IRCSERVER'],
#                             nick=("%s%s" % (config['IRCBOTBASENAME'], "-qu")),
#                             allowForce=True,
#                             channels=[config['IRCCHANNEL']],
#                             notify_events={
#                               'started': 0,
#                               'finished': 0,
#                               'success': 0,
#                               'failure': 0,
#                               'exception': 0,
#                               'successToFailure': 1,
#                               'failureToSuccess': 1,
#                             }))

#IRC Bot, very chatty, in a configurable channel, probably it's own
c['status'].append(words.IRC(host=config['IRCSERVER'],
#                             nick=("%s%s" % (config['IRCBOTBASENAME'], "-ch")),
                             #If we just have one bot, we only need one name
                             nick=config['IRCBOTBASENAME'],
                             allowForce=True,
                             channels=[config['IRCBOTCHANNEL']],
                             notify_events={
                               'started': 1,
                               'finished': 1,
                               'success': 1,
                               'failure': 1,
                               'exception': 1,
                               'successToFailure': 1,
                               'failureToSuccess': 1,
                             }))

####### DB URL

c['db'] = {
    'db_url' : "sqlite:///state.sqlite",
}
